package v5

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"os"
)

const (
	WALLET_FILE_NAME = "wallet.dat"
)

type Wallets struct {
	//地址集合
	MapAddress map[string]*Wallet
}

func (ws *Wallets) S() []byte {
	//第一种 gob序列化
	//高版本下不支持这种
	//panic: gob: type elliptic.p256Curve has no exported fields
	//var buffer bytes.Buffer
	////gob.Register(elliptic.P256()) //否则会序列化失败,目前高版本注册了也会因为小写失败, .但是目前设置了 gob:"-" 还是序列化不了
	////所以这直接去掉,不序列化该字段,用D坐标来序列化,在反序列化的时候再组装一次该字段的数据就行了
	//enc := gob.NewEncoder(&buffer)
	//err := enc.Encode(ws)
	//if err != nil {
	//	log.Panic(err)
	//}
	//return buffer.Bytes()

	//第二种json序列化
	json, err := json.Marshal(ws)
	if err != nil {
		log.Panic(err)
	}
	return json
}

func ds(c elliptic.Curve, data []byte) *Wallets {
	//高版本不支持,下面以json暂时替代
	//panic: gob: type elliptic.p256Curve has no exported fields
	//第一种: gob序列化
	//var wallets Wallets
	////gob.Register(elliptic.P256()) //注册高版本中不生效.但是目前设置了 gob:"-" 还是序列化不了
	//dec := gob.NewDecoder(bytes.NewReader(data))
	//dec.Decode(&wallets)
	//第二种: json序列化
	var wallets Wallets
	err := json.Unmarshal(data, &wallets)
	if err != nil {
		log.Panic(err)
	}

	//
	mapAddress := wallets.MapAddress
	for k, wallet := range mapAddress {
		var d, x, y big.Int
		d.SetBytes(wallet.D)
		//前面是xy拼接的
		x.SetBytes(wallet.PublicKey[:len(wallet.PublicKey)/2])
		y.SetBytes(wallet.PublicKey[len(wallet.PublicKey)/2:])
		publicKey := ecdsa.PublicKey{
			c,
			&x,
			&y,
		}
		privateKey := ecdsa.PrivateKey{
			publicKey,
			&d,
		}
		wallet.PrivateKey = &privateKey
		wallets.MapAddress[k] = wallet
	}
	return &wallets
}

func ListAddresses() *Wallets {
	_, err := os.Stat(WALLET_FILE_NAME)
	if os.IsNotExist(err) {
		log.Panic("钱包文件不存在!")
	}
	data, err := os.ReadFile(WALLET_FILE_NAME)
	if err != nil {
		log.Panic(err)
	}
	//反序列化
	ws := ds(elliptic.P256(), data)
	return ws
}

// 根据地址找钱包
func GetWalletByAddress(address string) *Wallet {
	listAddresses := ListAddresses()
	for s, wallet := range listAddresses.MapAddress {
		if s == address {
			return wallet
		}
	}
	return nil
}

func NewWallets() string {
	wallet := NewWallet()
	address := wallet.GetAddress()
	//存入文件
	_, err := os.Stat(WALLET_FILE_NAME)
	if os.IsNotExist(err) {
		fmt.Printf("WriteFile[%s] is IsNotExist! \n", WALLET_FILE_NAME)
		m := make(map[string]*Wallet)
		m[address] = wallet
		wallets := Wallets{
			MapAddress: m,
		}
		//序列化写入
		s := wallets.S()
		//在 Go 中，八进制数以 0 开头。例如：
		//0644 表示用户可读写，组和其他用户只读。
		//0755 表示用户可读写执行，组和其他用户可读执行。
		err = os.WriteFile(WALLET_FILE_NAME, s, 0644)
		if err != nil {
			log.Panic(err)
		}
		fmt.Printf("first WriteFile[%s] is ok! \n", WALLET_FILE_NAME)
	} else {
		fmt.Printf("WriteFile[%s] is IsExist! \n", WALLET_FILE_NAME)
		data, err := os.ReadFile(WALLET_FILE_NAME)
		//反序列化
		ws := ds(elliptic.P256(), data)
		//赋予新值
		ws.MapAddress[address] = wallet
		//再序列化
		s := ws.S()
		//ws写回文件
		err = os.WriteFile(WALLET_FILE_NAME, s, 0644)
		if err != nil {
			log.Panic(err)
		}
	}
	return address
}
